package io.ziyt.mouse;

import io.net.bullfrog.net.prots.udp.nio.multicast.MulticastChannel;

import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.event.InputEvent;
import java.io.IOException;
import java.net.*;
import java.nio.ByteBuffer;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class MouseApp {
    static Robot robot;
    static Point point;
    public static final int MESSAGE_PORT = 9999;
    private static boolean rigthClick = false;
    private static boolean longpress = false;
    private static boolean singleClick = false;
    private static boolean doubleClick = false;
    private static boolean loop = false;
    private static ScheduledExecutorService releaseTask = Executors.newScheduledThreadPool(3);
    private static Map<MulticastChannel,SocketAddress> socketAddressMap=new HashMap<>();

    public static void main(String[] args) throws AWTException,
            InterruptedException, IOException {

        Toolkit.getDefaultToolkit().getSystemClipboard().setContents(Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null),new ClipboardOwner() {

            @Override
            public void lostOwnership(Clipboard clipboard, Transferable contents) {
                // 如果不暂停一下，经常会抛出IllegalStateException
                // 猜测是操作系统正在使用系统剪切板，故暂时无法访问
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 取出文本并进行一次文本处理
//                if (clipboard.isDataFlavorAvailable(DataFlavor.stringFlavor)) {
                    try {
                        String text = (String) clipboard.getData(DataFlavor.stringFlavor);
                        if (text != null) {
                            socketAddressMap.forEach((c,a)->c.send(ByteBuffer.wrap(text.getBytes()), a));
                        }
                        Toolkit.getDefaultToolkit().getSystemClipboard().setContents(Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null),this::lostOwnership);
                    } catch (UnsupportedFlavorException | IOException e) {
                        e.printStackTrace();
                    }

//                }
            }
        });
        robot = new Robot();
        MulticastChannel multicastChannel = new MulticastChannel(StandardProtocolFamily.INET);
        multicastChannel.bind(new InetSocketAddress(MESSAGE_PORT));
//        multicastChannel.joinGroup(InetAddress.getByName("230.0.0.1"), NetworkInterface.getByInetAddress(InetAddress.getByName("127.0.0.1")));
        multicastChannel.startReceive((channel, byteBuffer, socketAddress, socketAddress1) -> {
            socketAddressMap.put(channel,socketAddress1);

            if (byteBuffer.hasRemaining()) {
                byte[] buff = new byte[byteBuffer.remaining()];
                byteBuffer.get(buff);
                if ("hello server".equals(new String(buff))) {
                    channel.send(ByteBuffer.wrap("hello client".getBytes()), socketAddress1);
                    System.out.println("收到客户端握手消息");
                    return;
                }
                if (!rigthClick) {
                    controlMouseByDate(channel, socketAddress, socketAddress1, getByteArraysByString(new String(buff)));
                }

//                Toolkit.getDefaultToolkit().getSystemClipboard().addFlavorListener(new FlavorListener() {
//                    @Override
//                    public void flavorsChanged(FlavorEvent e) {
//                        Clipboard clipboard = (Clipboard) e.getSource();
//                        Transferable content = clipboard.getContents(this);
//                        if (content != null && content.isDataFlavorSupported(DataFlavor.stringFlavor)) {
//                            try {
//                                String data = (String) content.getTransferData(DataFlavor.stringFlavor);
//                                channel.send(ByteBuffer.wrap(data.getBytes()), socketAddress1);
//                            } catch (UnsupportedFlavorException | IOException e1) {
//                                e1.printStackTrace();
//                            }
//                        }
//                    }
//                });
//                Transferable t = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null);
//                try {
//                    String readText = (String)t.getTransferData(DataFlavor.stringFlavor);
//                    System.out.println(readText);
//                    channel.send(ByteBuffer.wrap(readText.getBytes()),socketAddress1);
//                } catch (UnsupportedFlavorException | IOException e) {
//                    e.printStackTrace();
//                }
            }
        }, 5, 100);
//        UdpServiceUtils udpServiceUtils = UdpServiceUtils.getInstence();
//        try {
//            while (true) {
//                String reciveData = udpServiceUtils.reciveUpdData();
//                if (reciveData.equals("")) {
//                    break;
//                }
//                byte[] recvData = getByteArraysByString(reciveData);
//
//                controlMouseByDate(recvData);
//            }
//        } catch (Exception e) {
//            // TODO Auto-generated catch block
//            e.printStackTrace();
//        }
    }

    private static NetworkInterface getUp() throws SocketException {
        NetworkInterface target = null;
        Enumeration<NetworkInterface> enumeration = NetworkInterface.getNetworkInterfaces();
        while (enumeration.hasMoreElements()) {
            NetworkInterface networkInterface = enumeration.nextElement();
            Enumeration<InetAddress> addressEnumeration = networkInterface.getInetAddresses();
//            while (addressEnumeration.hasMoreElements()) {
//                System.out.println(addressEnumeration.nextElement().toString());
//            }
            if (!networkInterface.isLoopback() && networkInterface.isUp() && !networkInterface.isVirtual()) {
                target = networkInterface;
//                System.out.println("=====================" + target.isLoopback() + " " + target.isUp() + " " + target.isVirtual() + " " + target.getDisplayName());
                break;
            }

        }
        return target;
    }

    public static byte[] getByteArraysByString(String data) {
        String revc = data.replace("[", "");
        revc = revc.replace("]", "");
        if (revc.contains(",")) {
            String[] datas = revc.split(",");

            byte[] byteDatas = new byte[datas.length];

            for (int i = 0; i < datas.length; i++) {
                byteDatas[i] = Byte.valueOf(datas[i].trim());
            }
            return byteDatas;
        } else {
            byte[] byteData = {Byte.valueOf(revc)};
            return byteData;
        }
    }

    public static void controlMouseByDate(MulticastChannel channel, SocketAddress local, SocketAddress remote,
                                          byte[] datas) {
        if (datas == null || datas.length == 0) {
            return;
        }
        if (loop && datas[0] != 4) {
            return;
        }
        if (longpress && datas[0] != 3 && datas[0] != 4) {
            robot.mouseRelease(InputEvent.BUTTON1_MASK);
            longpress = false;
            return;
        }
        switch (datas[0]) {
            // 左键单击
            case 1:
                if (singleClick) {
                    break;
                }
                singleClick = true;
                robot.mousePress(InputEvent.BUTTON1_MASK);// 按下左键
                robot.mouseRelease(InputEvent.BUTTON1_MASK);// 释放左键
                releaseTask.schedule(() -> {
                    singleClick = false;
                }, 50, TimeUnit.MILLISECONDS);
                break;

            // 左键双击
            case 2:
                if (doubleClick) {
                    break;
                }
                robot.mousePress(InputEvent.BUTTON1_MASK);// 按下左键
                robot.mouseRelease(InputEvent.BUTTON1_MASK);// 释放左键
                robot.delay(100);// 停顿100毫秒,即0.1秒
                robot.mousePress(InputEvent.BUTTON1_MASK);// 按下左键
                robot.mouseRelease(InputEvent.BUTTON1_MASK);// 释放左键
                releaseTask.schedule(() -> {
                    doubleClick = false;
                }, 50, TimeUnit.MILLISECONDS);
                break;

            // 鼠标滑动;
            case 3:
                // 获得当前的鼠标坐标
                point = MouseInfo.getPointerInfo().getLocation();
                int posX = (int) point.getX();
                int posY = (int) point.getY();

                int offset_x = byteArrayToInt_x(datas);
                int offset_y = byteArrayToInt_y(datas);

                robot.mouseMove(posX - offset_x, posY - offset_y);
                break;

            // 滚轮
            case 4:
                loop = true;
                int wheelAmt = byteArrayToInt_scroll(datas);
                if (wheelAmt > 0) {
                    wheelAmt = 1;
                } else if (wheelAmt < 0) {
                    wheelAmt = -1;
                } else {
                    wheelAmt = 0;
                }

//                System.out.println(wheelAmt);
                robot.mouseWheel(wheelAmt);
                releaseTask.schedule(() -> {
                    loop = false;
                }, 500, TimeUnit.MILLISECONDS);
                break;
            case 5:
                rigthClick = true;
                //右键单击
                robot.mousePress(InputEvent.BUTTON3_MASK);
                robot.mouseRelease(InputEvent.BUTTON3_MASK);
                releaseTask.schedule(() -> {
                    rigthClick = false;
                }, 500, TimeUnit.MILLISECONDS);
                break;
            case 6:
                //长按进入选择状态
                robot.mousePress(InputEvent.BUTTON1_MASK);
                longpress = true;
                break;
            default:
                break;
        }
    }

    public static int byteArrayToInt_x(byte[] data) {
        byte[] byte_x = new byte[4];
        byte_x[0] = data[1];
        byte_x[1] = data[2];
        byte_x[2] = data[3];
        byte_x[3] = data[4];

        int value;
        value = (int) ((byte_x[3] & 0xFF) | ((byte_x[2] & 0xFF) << 8)
                | ((byte_x[1] & 0xFF) << 16) | ((byte_x[0] & 0xFF) << 24));
        return value;
    }

    public static int byteArrayToInt_y(byte[] data) {
        byte[] byte_y = new byte[4];
        byte_y[0] = data[5];
        byte_y[1] = data[6];
        byte_y[2] = data[7];
        byte_y[3] = data[8];
        int value;
        value = (int) ((byte_y[3] & 0xFF) | ((byte_y[2] & 0xFF) << 8)
                | ((byte_y[1] & 0xFF) << 16) | ((byte_y[0] & 0xFF) << 24));
        return value;
    }

    public static int byteArrayToInt_scroll(byte[] data) {
        byte[] byte_scroll = new byte[4];
        byte_scroll[0] = data[1];
        byte_scroll[1] = data[2];
        byte_scroll[2] = data[3];
        byte_scroll[3] = data[4];
        int value;
        value = (int) ((byte_scroll[3] & 0xFF) | ((byte_scroll[2] & 0xFF) << 8)
                | ((byte_scroll[1] & 0xFF) << 16) | ((byte_scroll[0] & 0xFF) << 24));
        return value;
    }
}
